﻿using System.Runtime.CompilerServices;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 3D形状布局，永远符合3D布局的形状 
/// </summary>
public class Bhv3DShapeLayout : MonoBehaviour
{

    [System.Serializable]
    public struct TowerInfo
    {
        [Title("=====  基础值 =====")]
        public int bottomCount;
        public float bottomRadius;
        public float bottomSpin;

        [Title("=====  最高值/偏移值 =====")]
        public int offsetCount;
        public float offsetRadius;
        public float offsetTowerSpin;
        [Title("=====  根据CellSize排列 =====")]

        /// <summary>
        /// 保持 Bottom 尺寸,不保存可能会从更小的尺寸算起
        /// </summary>
        public bool autoSize;

    }

    public TowerInfo towerInfo;

    public Vector3 cellSize;


    public enum Shape
    {
        Tower,
        Heap,
        Plane
    }

    public Shape shape = Shape.Tower;


    public delegate Vector3[] GetLinePositionsDelegate(float radius, int count, float offsetAngle = 0);


    private Vector3[] _sortPosition;

    private static List<Vector3> _tempList = new List<Vector3>();

    private void OnValidate()
    {
        int childCount = this.transform.childCount;

        // print(string.Join(",", GetTowerHeights(childCount, this.towerInfo.bottomCount, this.towerInfo.totalCount)));

        switch (shape)
        {
            case Shape.Tower:
            case Shape.Heap:
            case Shape.Plane:
                _sortPosition = GetTowerPositions(cellSize, this.transform.childCount, this.shape, this.towerInfo);
                break;
        }

        this.UpdateLayout();
    }

    /// <summary>
    /// 获取每层塔应该堆叠的对象数量
    /// </summary>
    /// <param name="childCount"></param>
    /// <param name="bottomCount"></param>
    /// <param name="offsetCount"></param>
    /// <returns></returns>
    private static int[] GetTowerHeights(int childCount, int bottomCount, int offsetCount)
    {
        int towerHeight = 0;
        var temp = new List<int>();
        int maxBottomCount = bottomCount;
        if (maxBottomCount == 0) maxBottomCount = 1;

        while (childCount > 0)
        {
            temp.Add(bottomCount);
            childCount -= bottomCount;
            bottomCount -= offsetCount;
            //记录含有对象数量最多的塔层
            if (bottomCount >= maxBottomCount)
            {
                maxBottomCount = bottomCount;
            }

            towerHeight++;
            if (bottomCount <= 0)
            {
                break;
            }
        }

        //处理剩余数量的元素
        var temp2 = temp.ToArray();
        int max = maxBottomCount;
        if (childCount >= maxBottomCount)
        {
            int repeatMaxCount = childCount / maxBottomCount;
            childCount = childCount % maxBottomCount;

            for (int i = 0; i < repeatMaxCount; i++)
            {
                int index = temp.IndexOf(maxBottomCount);
                if (index != -1)
                {
                    temp.Insert(index, maxBottomCount);
                }
            }
        }

        //将多余出的子对象根据数值插入到 之前排序好的对象中（比较数值大小依次放置来增加层数)
        while (childCount > 0)
        {
            int maxValue = 0;
            for (int i = 0; i < temp2.Length; i++)
            {
                if (i > maxValue)
                {
                    maxValue = temp2[i];//i
                }
            }

            childCount -= maxValue;
            if (maxValue <= 0)
            {
                break;
            }
            else
            {
                int index = temp.IndexOf(maxValue);
                if (index != -1)
                {
                    temp.Insert(index, maxValue);
                }
            }

        }

        return temp.ToArray();

    }

    public void UpdateLayout()
    {
        foreach (Transform child in transform)
        {
            child.transform.position = new Vector3(999, 999, 999);
        }
        for (int i = 0; i < _sortPosition.Length; i++)
        {
            if (i >= this.transform.childCount) return;
            var child = this.transform.GetChild(i);
            child.transform.localPosition = _sortPosition[i];
        }
    }

    /// <summary>
    /// 推算出 塔应该 bottom count 设置为多少比较合适
    /// </summary>
    /// <param name="childCount"></param>
    /// <param name="maxBottom"></param>
    /// <param name="offsetCount"></param>
    /// <param name="topCount"></param>
    /// <returns></returns>
    public static int GetFitTowerBottomCount(int childCount, int maxBottom, int offsetCount, int topCount = 1)
    {
        if (offsetCount == 0)
        {
            if (childCount > maxBottom)
            {
                return maxBottom;
            }
            else
            {
                return childCount;
            }
        }

        while (childCount > 0)
        {
            childCount -= topCount;
            if (childCount <= 0)
            {
                break;
            }
            else
            {
                topCount += offsetCount;
            }
        }
        return Mathf.Clamp(topCount, 1, maxBottom);
    }


    private static float GetRadiusScaleByCount(int height)
    {
        float delta = 0.5f;
        switch (height)
        {
            case 0: delta = 0; break;
            case 1: delta = 0; break;
            case 2: delta = 0.5f; break;
            case 3: delta = 0.67f; break;
            case 4: delta = 1.0f; break;
            case 5: delta = 1.05f; break;
            case 6: delta = 1.15f; break;
            default:
                delta = 1.15f + (height - 6) * 0.14f;
                break;
        }

        return delta;
    }


    /// <summary>
    /// 获取塔各层元素的坐标,自动适配 生成3D的塔型
    /// </summary>
    /// <param name="cellSize">细胞尺寸</param>
    /// <param name="childCount">塔对象数量</param>
    /// <param name="towerInfo">塔的信息</param>
    /// <param name="GetLinePositions">方法，获取每层塔的计算函数</param>
    /// <returns></returns>
    public static Vector3[] GetTowerPositions(Vector3 cellSize, int childCount, Shape shape, TowerInfo towerInfo)
    {

        float bottomRadius = towerInfo.bottomRadius;
        float offsetRadius = towerInfo.offsetRadius;
        int bottomCount = towerInfo.bottomCount;
        int offsetCount = towerInfo.offsetCount;
        float offsetTowerSpin = towerInfo.offsetTowerSpin;

        //自动算出 底部数量
        if (towerInfo.autoSize)
        {
            // if (offsetCount != 0)
            // {
            bottomCount = GetFitTowerBottomCount(childCount, bottomCount, offsetCount);
            // }
        }

        ///自动尺寸(改动)
        var heights = GetTowerHeights(childCount, bottomCount, offsetCount);
        var filters = heights.GroupBy(p => p).Select(p => p.Key).ToList(); //过滤后的元素

        //自动算出 底部半径
        if (towerInfo.autoSize)
        {
            float delta = GetRadiusScaleByCount(heights.Length);

            if (shape == Shape.Tower)
            {

                bottomRadius = cellSize.x * (delta * 2f);
                offsetRadius = 0;
            }
            else
            {
                bottomRadius = cellSize.x * bottomCount;
                offsetRadius = cellSize.x;
            }

        }

        var list = new List<Vector3>();

        if (shape == Shape.Plane) //平面堆叠计算 (由远到近)
        {
            for (int i = 0; i < heights.Length; i++)
            {
                Vector3[] ringPositions;

                int count = heights[i];//bottomCount - i * totalCount;
                int filterIndex = filters.IndexOf(count); //过滤排序序号
                float offsetAngle = 0;
                float radius = 0;
                radius = bottomRadius - filterIndex * offsetRadius;
                radius = Mathf.Max(radius, cellSize.z);

                ringPositions = GetLinePositions(radius, count, offsetAngle);

                foreach (var ring in ringPositions)
                {
                    list.Add(new Vector3(ring.x, 0, ring.y - (heights.Length - 1) * cellSize.z * 0.5f) + new Vector3(0, 0, i * cellSize.z));
                }
            }

        }
        else //立体堆叠计算
        {
            for (int i = 0; i < heights.Length; i++)
            {
                Vector3[] ringPositions;

                int count = heights[i];//bottomCount - i * totalCount;
                int filterIndex = filters.IndexOf(count); //过滤排序序号
                float offsetAngle = 0;
                float radius = 0;

                if (towerInfo.autoSize && shape == Shape.Tower)
                {
                    //特殊处理缩放尺寸
                    radius = cellSize.x * GetRadiusScaleByCount(count) * 0.5f;
                    radius = Mathf.Min(radius, cellSize.x);
                }
                else
                {
                    radius = bottomRadius - filterIndex * offsetRadius;
                    radius = Mathf.Max(radius, cellSize.x);
                }

                offsetAngle = 0 - filterIndex * offsetTowerSpin;


                // print("" + i + ">" + radius);

                //不同塔的情况
                if (shape == Shape.Tower)
                {
                    ringPositions = GetRingPositions(radius, count, offsetAngle);
                }
                else
                {
                    ringPositions = GetLinePositions(radius, count, offsetAngle);
                }

                foreach (var ring in ringPositions)
                {
                    list.Add(ring + new Vector3(0, i * cellSize.y, 0));
                }
            }

        }


        return list.ToArray();
    }


    public static Vector3[] GetLinePositions(float width, int count, float offsetZ = 0)
    {
        _tempList.Clear();
        if (count <= 1)
        {
            return new Vector3[] { Vector3.zero };
        }

        //1

        for (int i = 0; i < count; i++)
        {
            float x = (i + 0.5f) / (float)(count) - 0.5f;
            Vector3 pos = new Vector3(x * width, 0, 0);
            _tempList.Add(pos);
        }
        return _tempList.ToArray();

    }


    public static Vector3[] GetRingPositions(float radius, int count, float offsetAngle = 0)
    {
        _tempList.Clear();

        if (count <= 1)
        {
            return new Vector3[] { Vector3.zero };
        }

        for (int i = 0; i < count; i++)
        {
            float angle = i * 360f / count + offsetAngle;
            float x = Mathf.Cos(Mathf.Deg2Rad * angle) * radius;
            float z = Mathf.Sin(Mathf.Deg2Rad * angle) * radius;
            Vector3 pos = new Vector3(x, 0, z);
            _tempList.Add(pos);
        }
        return _tempList.ToArray();
    }


}
